package handler

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"
	"math/rand"
	"service_base_shop/order_srv/global"
	"service_base_shop/order_srv/model"
	protopb "service_base_shop/order_srv/proto"
	"service_base_shop/order_srv/utils"
	"strconv"
	"strings"
	"time"
)

type OrderSrv struct {
}





//获取订单数量
func (this *OrderSrv) GetOrderInfo(ctx context.Context, req *protopb.GetOrderInfoReq) (*protopb.GetOrderInfoRep, error) {
	order_info := &protopb.GetOrderInfoRep{}
	var pay_num int64
	global.DB.Table("lr_order").Where("status = 10 and del = 0 and uid = ?", req.UserId).Count(&pay_num)
	var rec_num int64
	global.DB.Table("lr_order").Where(`status = 30 and back = "0" and del = 0 and uid = ?`, req.UserId).Count(&rec_num)
	var finish_num int64
	global.DB.Table("lr_order").Where(`status > 30  and back = "0" and del = 0 and uid = ?`, req.UserId).Count(&finish_num)
	var refund_num int64
	global.DB.Table("lr_order").Where(` back > "0" and del = 0 and uid = ?`, req.UserId).Count(&refund_num)

	order_info.PayNum = pay_num
	order_info.RecNum = rec_num
	order_info.FinishNum = finish_num
	order_info.RefundNum = refund_num
	return order_info, nil
}
//
func (this *OrderSrv) GetOrderList(ctx context.Context, req *protopb.GetOrderListReq) (*protopb.GetOrderListRep, error) {
	page := req.Page
	if page == 0 {
		page = 1
	}
	order_type := req.OrderType
	order_where := "o.del = 0 and " + ` o.back = "0" and `
	switch order_type {
	case "pay":
		order_where += " o.status = 10 "
		break
	case "deliver":
		order_where += " o.status = 20 "
		break
	case "receive":
		order_where += " o.status = 30 "
		break
	case "evaluate":
		order_where += " o.status = 40 "
		break
	case "finish":
		order_where += " o.status in (40,50) "
		break
	default:
		order_where += " o.status = 10 "
		break
	}
	order_where += " and o.uid = ?"

	var pro_count int64 = 0
	var count int64 = 0
	eachpage := 7
	global.DB.Table("lr_order as o").Where(order_where).Count(&count)
	//order_list := []map[string]interface{}{}
	order_list := []*protopb.OrderInfo{}
	if err := global.DB.Table("lr_order as o").
		Where(order_where, req.UserId).
		Select("o.id,o.status,o.order_sn,o.pay_sn,o.price,o.type,o.product_num").
		Offset((int(page) - 1) * eachpage).
		Limit(eachpage).
		Find(&order_list).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			ret_list, _ := json.Marshal(order_list)
			return &protopb.GetOrderListRep{
				OrderList: string(ret_list),
				EachPage:  0,
			}, nil
		} else {
			return nil, status.Errorf(codes.NotFound, "查询错误")
		}
	}
	order_status := map[string]string{"0": "已取消", "10": "待付款", "20": "待发货", "30": "待收货", "40": "待评价", "50": "交易完成", "51": "交易关闭"}
	order_product := model.OrderProduct{}
	for _, v := range order_list {
		global.DB.Table("lr_order_product").Where("order_id = ?",v.Id).Select("pid,name,price,photo_x").Order("id asc").Take(&order_product)
		fmt.Println(order_product.Price)
		v.Desc = order_status[utils.Int64ToString(v.Status)]
		global.DB.Table("lr_order_product").Where("order_id = ?", v.Id).Count(&pro_count)
		v.ProCount = pro_count
		v.Pid = order_product.Pid
		v.Name = order_product.Name
		v.PriceYh = order_product.Price
		v.PhotoX= order_product.PhotoX
		if v.PaySn == "" {
			v.PaySn = "-"
		}
	}
	ret_order_list, _ := json.Marshal(order_list)
	return &protopb.GetOrderListRep{
		EachPage:  int64(eachpage),
		OrderList: string(ret_order_list),
	}, nil
}

func (this *OrderSrv) GetOrderDetails(ctx context.Context, req *protopb.GetOrderDetailsReq) (*protopb.GetOrderDetailsRep, error) {
	order_id := req.OrderId
	user_id := req.UserId
	order_info := model.Order{}
	if err := global.DB.Table("lr_order").
		Where("del = 0 and id = ? and uid = ? ",order_id,user_id).
		Select("id,order_sn,shop_id,status,addtime,price,type,post,tel,receiver,address_xq,remark").
		Take(&order_info).Error; err != nil{
		if errors.Is(err,gorm.ErrRecordNotFound) {
			return &protopb.GetOrderDetailsRep{},status.Errorf(codes.NotFound,"订单不存在，请联系客服")
		}
	}
	order_product := []model.OrderProduct{}
	if err := global.DB.Table("lr_order_product").
		Where("order_id = ? ",order_id).
		Find(&order_product).Error; err != nil{
		if errors.Is(err,gorm.ErrRecordNotFound) {
			return &protopb.GetOrderDetailsRep{},status.Errorf(codes.NotFound,"订单详情不存在，请联系客服")
		}
	}
	order_info.OrderProduct = order_product
	shangcheng := model.Shangchang{}
	if err := global.DB.Table("lr_shangchang").
		Where("id = ? ",order_info.OrderCreate.ShopId).
		Select("shop_name").
		Find(&shangcheng).Error; err != nil{
		if errors.Is(err,gorm.ErrRecordNotFound) {
			return &protopb.GetOrderDetailsRep{},status.Errorf(codes.NotFound,"店铺不存在，请联系客服")
		}
	}

	var  post_price float32
	if order_info.OrderCreate.Post != 0 {
		global.DB.Table("lr_post").Where("id = ?", order_info.OrderCreate.Post).Select("price").Take(&post_price)
	}else {
		post_price = 0
	}


	//订单状态
	order_status := map[string]string{"0":"已取消","10":"待付款","20":"待发货","30":"待收货","40":"已收货","50":"交易完成"}
	order_info.OrderStatus = order_status[strconv.Itoa(order_info.OrderCreate.Status)]
	//支付类型
	pay_type := map[string]string{"cash":"现金支付","alipay":"支付宝","weixin":"微信支付"}
	order_info.PayType = pay_type[order_info.Type]

	ret_order_info := protopb.OrderInfo{
		Id: order_info.Id,
		Status: int64(order_info.OrderCreate.Status),
		PayType: pay_type[order_info.OrderCreate.Type],
		Price: order_info.OrderCreate.Price,
		Tel: order_info.OrderCreate.Tel,
		Type: order_info.OrderCreate.Type,
		OrderStatus: order_info.OrderStatus,
		Receiver: order_info.OrderCreate.Receiver,
		Remark: order_info.OrderCreate.Remark,
		Addtime: utils.Int64ToTime(order_info.Addtime),
		Yunfei: float64(post_price),
		ShopId: order_info.OrderCreate.ShopId,
		ShopName: shangcheng.Name,
		Post: order_info.OrderCreate.Post,
		OrderSn: order_info.OrderCreate.OrderSn,
		AddressXq: order_info.OrderCreate.AddressXq,

	}
	order_detail := []*protopb.OrderDetailsInfo{}
	for _,v := range order_info.OrderProduct{
		order_detail = append(order_detail,&protopb.OrderDetailsInfo{
			Id: v.Id,
			Addtime: utils.Int64ToTime(v.Addtime),
			Pid: v.Pid,
			Price: v.Price,
			PhotoX: v.PhotoX,
			PaySn: v.PaySn,
			ProBuff: v.ProBuff,
			ProGuige: v.ProGuige,
			Name: v.Name,
			Num: int64(v.Num),
			OrderId: v.OrderId,
		})
	}

	return &protopb.GetOrderDetailsRep{
		Order: &ret_order_info,
		Details: order_detail,
	},nil
}

func (this *OrderSrv) GetOrderRefundLists(ctx context.Context, req *protopb.GetOrderRefundReq) (*protopb.GetOrderRefundRep, error) {
	page := req.Page
	if page == 0 {
		page = 1
	}
	//获取总页数
	var count int64
	refund_where := `uid = ? and back > "0"`
	if err := global.DB.Table("lr_order").Where(refund_where,req.UserId).Count(&count).Error; err != nil{
		if errors.Is(err,gorm.ErrRecordNotFound) {
			return &protopb.GetOrderRefundRep{
				List: []*protopb.OrderRefundInfo{},
			}, nil
		}
	}
	refund_list := []model.Order{}
	if err := global.DB.Table("lr_order").
		Where(refund_where,req.UserId).
		Select("id,price,order_sn,product_num,back,back_addtime").
		Order("back_addtime desc").
		Offset(int(page - 1) * 6).Limit(6).Find(&refund_list).Error; err != nil{
		if errors.Is(err,gorm.ErrRecordNotFound) {
			return &protopb.GetOrderRefundRep{
				List: []*protopb.OrderRefundInfo{},
			}, nil
		}
	}
	List := []*protopb.OrderRefundInfo{}
	order_product := model.OrderProduct{}
	refund_status := map[string]string{"1":"退款申请中","2":"已退款","3":"处理中","4":"已拒绝"}
	for _,v := range refund_list{
		 var pro_count int64
		global.DB.Table("lr_order_product").Where("order_id = ?", v.Id).Count(&pro_count)
		global.DB.Table("lr_order_product").Where("order_id = ?", v.Id).Select("pid,name,price,photo_x").Order("id asc").Take(&order_product)
		List = append(List,&protopb.OrderRefundInfo{
			Desc: refund_status[v.Back],
			PhotoX: order_product.PhotoX,
			Pid: order_product.Pid,
			Name: order_product.Name,
			PriceYh: order_product.Price,
			Id: v.Id,
			Price: v.Price,
			OrderSn: v.OrderSn,
			ProductNum: int64(v.ProductNum),
			Back: v.Back,
			BackAddtime: utils.Int64ToTime(v.BackAddtime),
			ProCount: pro_count,
		})
	}
	return &protopb.GetOrderRefundRep{
		List: List,
	}, nil
}

func (this *OrderSrv) BuyCart (ctx context.Context, req *protopb.BuyCartReq) (*protopb.BuyCartRep, error) {
	add := model.Address{}
	yunfei := model.Post{}
	add_ret := global.DB.Table("lr_address").Where("uid = ? and is_default = 1",req.UserId).Take(&add)
	id := StrToArr(req.CartId)
	pro := []*model.ShoppingCharOrGoods{}
	vou := []model.UserVoucher{}
	var  price float64 = 0 //总价
	check_cart := model.ShoppingChar{}
	for _,v := range id{
		if ret := global.DB.Table("lr_shopping_char").Where("id = ?",v).Take(&check_cart); ret.RowsAffected == 0{
			return nil,status.Errorf(codes.NotFound,"非法请求")
		}
		goods_info := model.ShoppingCharOrGoods{}
		global.DB.Table("lr_shopping_char as c").
			Joins("left join lr_product as pr on c.pid = pr.id").
			Joins("left join lr_shangchang as sc on sc.id = c.shop_id").
			Select("pr.num, c.id,c.pid,sc.name,pr.name,pr.shop_id,pr.photo_x,pr.price_yh,c.num,c.buff,c.price").
			Where("c.uid = ? and c.id = ?",req.UserId,v).
			Take(&goods_info)
		aa,_ := json.Marshal(goods_info)
		fmt.Println(string(aa))
		goods_info.Product.PhotoX = global.DataUrl + goods_info.Product.PhotoX
		if goods_info.ShoppingChar.Buff != "" {
			goods_info.ShoppingChar.Zprice =goods_info.ShoppingChar.Price * float64(goods_info.ShoppingChar.Num)
		}else {
			goods_info.ShoppingChar.Price = goods_info.Product.PriceYh
			goods_info.ShoppingChar.Zprice =goods_info.ShoppingChar.Price * float64(goods_info.ShoppingChar.Num)
		}
		price += goods_info.ShoppingChar.Zprice
		pro = append(pro,&goods_info)

		//获取运费
		rets := global.DB.Table("lr_post").Where("pid = ?",goods_info.Product.ShopId).Take(&yunfei)
		//如果需要运费
		if rets.RowsAffected != 0 {
			price_max := goods_info.ShoppingChar.Price
			if price_max > 0 && price_max <= price {
				yunfei.Price = 0
			}
		}
		vou,_ = get_voucher(req.UserId,goods_info.ShoppingChar.Pid,id)

	}
	addemt := 0
	if add_ret.RowsAffected == 0 {
		addemt = 1;
	}
	fmt.Println(pro)
	pro_json,_ := json.Marshal(pro)
	vou_json,_ := json.Marshal(vou)
	yun_json,_ := json.Marshal(yunfei)
	add_json,_ := json.Marshal(add)
	return &protopb.BuyCartRep{Addemt: int64(addemt),Price: price,Pro: string(pro_json),Vou: string(vou_json),Yun: string(yun_json),CartId: req.CartId,Adds: string(add_json)},nil
}

func (this *OrderSrv) CreateOrder(ctx context.Context, req *protopb.CreateOrderReq) (*protopb.CreateOrderRep, error){
	cart_ids := StrToArr(req.CartId)

	shop := []model.ShoppingCharOrGoods{}
	num := 0
	var ozprice float64 = 0
	for _,v := range cart_ids{
		fmt.Println(v)
		goods_info := model.ShoppingCharOrGoods{}
		if ret := global.DB.Table("lr_shopping_char as c").
			Joins("left join lr_product as pr on c.pid = pr.id").
			Select("c.pid,c.num,c.shop_id,c.buff,c.price,pr.price_yh").
			Where("c.uid = ? and c.id = ?",req.UserId,v).
			Find(&goods_info); ret.RowsAffected == 0 {
			return nil, status.Errorf(codes.NotFound,"下单失败了哦！")
		}
		num = num + goods_info.ShoppingChar.Num
		if goods_info.ShoppingChar.Buff != "" {
			ozprice += goods_info.ShoppingChar.Price * float64(goods_info.ShoppingChar.Num)
		}else {
			goods_info.ShoppingChar.Price =  goods_info.Product.PriceYh
			ozprice += goods_info.ShoppingChar.Price * float64(goods_info.ShoppingChar.Num)
		}
		shop = append(shop,goods_info)
	}


	yunPrice := model.Post{}
	var yunPriceRet *gorm.DB
	data := model.OrderCreate{}
	if req.Yunfei != 0 {
		yunPriceRet = global.DB.Table("lr_post").Where("id = ?",req.Yunfei).Find(&yunPrice)
	}
	data.ShopId = shop[0].ShoppingChar.ShopId
	data.Uid = req.UserId

	if req.Yunfei != 0 && yunPriceRet.RowsAffected  > 0 {
		data.Post = yunPrice.Id
		data.Price = yunPrice.Price + ozprice
	}else {
		data.Post = 0
		data.Price = ozprice
	}
	data.Amount = data.Price
	if req.Vid > 0 {
		chk := model.OrderCreate{}
		vouinfo := model.UserVoucher{}
		vouinfo_ret := global.DB.Debug().Table("lr_user_voucher").Where("status = 1 and uid = ? and vid = ?",req.UserId,req.Vid).Find(&vouinfo)
		chk_ret := global.DB.Table("lr_order").Where("status > 0 and uid = ? and vid = ?",req.UserId,req.Vid).Find(&chk)
		if vouinfo_ret.RowsAffected == 0 || chk_ret.RowsAffected  == 0 {
			return nil, status.Errorf(codes.NotFound,"此优惠券不可用，请选择其他.")
		}
		if vouinfo.EndTime < time.Now().Unix() {
			return nil, status.Errorf(codes.NotFound,"优惠券已过期了")
		}
		if vouinfo.StartTime > time.Now().Unix() {
			return nil, status.Errorf(codes.NotFound,"优惠券还未生效")
		}
		data.Vid = req.Vid
		data.Amount = data.Price - vouinfo.Amount
	}
	data.Addtime = time.Now().Unix()
	data.Del = 0
	data.Type = req.Type
	data.Status = 10

	adds_id := req.Aid
	if adds_id < 1 {
		return nil, status.Errorf(codes.NotFound,"请选择收货地址")
	}

	adds_info := model.Address{}
	if ret := global.DB.Table("lr_address").Where("id = ?",adds_id).Take(&adds_info); ret.RowsAffected  == 0 {
		return nil, status.Errorf(codes.NotFound,"收货地址错误")
	}

	data.Receiver = adds_info.Name
	data.Tel = adds_info.Tel
	data.AddressXq = adds_info.AddressXq
	data.Code = adds_info.Code
	data.ProductNum = num
	data.Remark = req.Remark
	data.Back = "0"
	data.OrderSn = GenerateOrderSn(req.UserId)//生成唯一订单号
	tx := global.DB.Begin()
	if order_ret := tx.Table("lr_order").Create(&data); order_ret.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Errorf(codes.NotFound,"下单失败")
	}

	for _,v := range cart_ids{
		shops := model.ShoppingCharOrGoods{}
		global.DB.Table("lr_shopping_char as c").
			Joins("left join lr_product as pr on c.pid = pr.id").
			Where("c.uid = ? and c.id = ?",req.UserId,v).
			Select("c.pid,c.num,c.shop_id,c.buff,c.price,pr.name,pr.photo_x,pr.price_yh,pr.num").
			Find(&shops)

		if shops.ShoppingChar.Buff == ""  {
			shops.ShoppingChar.Price = shops.Product.PriceYh
		}
		buff_text := ""
		if shops.ShoppingChar.Buff != "" {
			buff := strings.Split(shops.ShoppingChar.Buff,",")
			buff_v := model.Guige{}
			for _,v := range buff {
				global.DB.Table("lr_guige").Where("id = ?",v).Select("name").Take(&buff_v)
				buff_text += buff_v.Name + " "
			}
		}


		OrderProduct := model.OrderProduct{}

		OrderProduct.Pid = shops.ShoppingChar.Pid
		OrderProduct.Name = shops.Product.Name
		OrderProduct.OrderId = data.Id
		OrderProduct.Price = shops.ShoppingChar.Price
		OrderProduct.PhotoX = shops.Product.PhotoX
		OrderProduct.ProBuff = buff_text
		OrderProduct.Addtime = time.Now().Unix()
		OrderProduct.Num = shops.ShoppingChar.Num
		OrderProduct.ProGuige = ""

		if order_ret := tx.Table("lr_order_product").Create(&OrderProduct); order_ret.RowsAffected == 0 {
			tx.Rollback()
			return nil, status.Errorf(codes.NotFound,"下单失败")
		}

		//调用库存服务 扣减库存
		_,err := global.JwtClient.ReduceProduct(context.Background(),&protopb.ReduceProductReq{GoodsId:OrderProduct.Pid,Num: int32(OrderProduct.Num)})
		if err != nil {
			tx.Rollback()
			return nil, err
		}
		//删除购物车
		del_cart := model.ShoppingChar{
			Id: int64(v),
		}
		if err := tx.Table("lr_shopping_char").Delete(&del_cart).Error; err != nil{
			tx.Rollback()
			return nil,status.Errorf(codes.NotFound,"下单失败22")
		}
	}
	tx.Commit()
	return &protopb.CreateOrderRep{
		OrderId: data.Id,
		OrderSn: data.OrderSn,
		PayType: data.Type,
	},nil
}


func (this *OrderSrv)OrderEdit(ctx context.Context, req *protopb.OrderEditReq) (*protopb.OrderEditRep,error)  {
	order := model.OrderCreate{}
	ret := global.DB.Table("lr_order").Where("uid = ? and  id = ? and del = 0",req.UserId,req.OrdrId).Take(&order)
	if ret.RowsAffected == 0 {
		return nil,status.Errorf(codes.NotFound,"订单信息错误")
	}
	updata := map[string]interface{}{}
	if req.Otype == "cancel" {
		updata["status"] = 0
	}else if req.Otype == "receive" {
		updata["status"] = 40
	}else if req.Otype == "refund" {
		order.Back = "1"
		updata["back"] = "1";
		updata["back_remark"] = "";
	}
	if ret := global.DB.Table("lr_order").Where("id = ?",req.OrdrId).Updates(&updata); ret.RowsAffected == 0 {
		return nil,status.Errorf(codes.NotFound,"操作失败")
	}
	return &protopb.OrderEditRep{},nil
}

func GenerateOrderSn(userId int64) string{
	//订单号的生成规则
	/*
		年月日时分秒+用户id+2位随机数
	*/
	now := time.Now()
	rand.Seed(time.Now().UnixNano())
	orderSn := fmt.Sprintf("%d%d%d%d%d",
		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute())
	return orderSn
}


func StrToArr(str string) []int  {
	arr := strings.Split(str,",")
	ids := []int{}
	for _,v := range arr{
		if v != "" {
			id,_ := strconv.Atoi(v)
			ids = append(ids,id)
		}
	}
	return ids
}


func StrToFloat(str interface{}) float64 {
	str1 := str.(string)
	num,_:= strconv.ParseFloat(str1,2)
	return num
}

//****************************
// 获取可用优惠券
//****************************
func get_voucher(uid,pid int64,cart_id []int) ([]model.UserVoucher,bool) {
	//计算总价
	var price float64 = 0
	for _,v := range cart_id{
		//pros := map[string]interface{}{}
		pros := model.ShoppingCharOrGoods{}
		if err := global.DB.Table("lr_shopping_char as sc").
			Joins("left join lr_product as p on p.id = sc.pid").
			Joins("left join lr_shangchang as s_c on s_c.id = sc.shop_id").
			Where("sc.uid = ? and sc.id = ?",uid,v).
			Select("sc.num,sc.price,sc.type").Take(&pros).Error; err != nil{
			if !errors.Is(err,gorm.ErrRecordNotFound) {
				return []model.UserVoucher{},false
			}
		}else {
			price += pros.ShoppingChar.Price * float64(pros.ShoppingChar.Num)
		}

	}
	vou_where := "uid = ? and status = 1 and start_time < ? and end_time > ? and full_money <= ?"
	start_time := time.Now().Unix()
	end_time := start_time
	vou := []model.UserVoucher{}
	if err := global.DB.Table("lr_user_voucher").Where(vou_where,uid,start_time,end_time,price).Order("addtime desc").Find(&vou).Error; err  != nil {
		if !errors.Is(err,gorm.ErrRecordNotFound) {
			return []model.UserVoucher{},false
		}
	}
	vouarr := []model.UserVoucher{}
	for _,v := range vou{
		chk_order := model.OrderCreate{}
		vou_info := model.Voucher{}
		chk_order_ret := global.DB.Table("lr_order").Where("uid = ? and vid = ? and status > 0",uid,v.Vid).Take(&chk_order)
		global.DB.Table("lr_voucher").Where("id = ?",v.Vid).Take(&vou_info)
		proid := strings.Split(vou_info.Proid,",")
		if vou_info.Proid=="all" || vou_info.Proid == "" || in_array(pid,proid) {
			if chk_order_ret.RowsAffected > 0 {
				arr := model.UserVoucher{}
				arr.Vid = v.Vid
				arr.FullMoney = v.FullMoney
				arr.Amount = v.Amount
				vouarr = append(vouarr,arr)
			}
		}

	}
	return vouarr,false
}

func in_array(str interface{},arr []string) bool {
	key := strconv.Itoa(int(str.(int64)))
	var set map[string]string
	set = make(map[string]string)
	for _, value := range arr{
		set[value] = value
	}
	if _, ok := set[key];ok {
		return true
	} else {
		return false
	}

}








